package domaine;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.MapKeyJoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import enumere.Couleur;

@Entity
@Table(name = "TOURS", schema = "ZELDAVOLO")
public class Tour implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static DeOrdre[] table;

	private enum DeOrdre {
		PLUS_GRANDE_SOMME {
			void calculerLinkGagnant(Tour tour) {
				int sommeRouge = 0, sommeNoir = 0, sommeBlanc = 0;
				int[] rouges = tour.desRouges();
				int[] noirs = tour.desNoirs();
				int[] blancs = tour.desBlancs();
				for (int i = 0; i < rouges.length; i++) {
					sommeRouge += rouges[i];
				}
				for (int i = 0; i < noirs.length; i++) {
					sommeNoir += noirs[i];
				}
				for (int i = 0; i < blancs.length; i++) {
					sommeBlanc += blancs[i];
				}
				if ((sommeRouge == sommeNoir && sommeRouge >= sommeBlanc)
						|| (sommeRouge == sommeBlanc && sommeRouge >= sommeNoir)
						|| (sommeNoir == sommeBlanc && sommeNoir >= sommeRouge))
					tour.gagnant = Couleur.GRIS;
				else if ((sommeRouge > sommeNoir && sommeRouge > sommeBlanc)
						|| sommeNoir == sommeBlanc && sommeNoir < sommeRouge)
					tour.gagnant = Couleur.ROUGE;
				else if ((sommeBlanc > sommeNoir && sommeBlanc > sommeRouge)
						|| sommeNoir == sommeRouge && sommeNoir < sommeBlanc)
					tour.gagnant = Couleur.BLANC;
				else if ((sommeNoir > sommeBlanc && sommeNoir > sommeRouge)
						|| sommeBlanc == sommeRouge && sommeBlanc < sommeNoir)
					tour.gagnant = Couleur.NOIR;
			}
		},
		PLUS_PETITE_SOMME {
			void calculerLinkGagnant(Tour tour) {
				int sommeRouge = 0, sommeNoir = 0, sommeBlanc = 0;
				int[] rouges = tour.desRouges();
				int[] noirs = tour.desNoirs();
				int[] blancs = tour.desBlancs();
				for (int i = 0; i < rouges.length; i++) {
					sommeRouge += rouges[i];
				}
				for (int i = 0; i < noirs.length; i++) {
					sommeNoir += noirs[i];
				}
				for (int i = 0; i < blancs.length; i++) {
					sommeBlanc += blancs[i];
				}
				if ((sommeRouge == sommeNoir && sommeRouge <= sommeBlanc)
						|| (sommeRouge == sommeBlanc && sommeRouge <= sommeNoir)
						|| (sommeNoir == sommeBlanc && sommeNoir <= sommeRouge))
					tour.gagnant = Couleur.GRIS;
				else if ((sommeRouge < sommeNoir && sommeRouge < sommeBlanc)
						|| sommeNoir == sommeBlanc && sommeNoir > sommeRouge)
					tour.gagnant = Couleur.ROUGE;
				else if ((sommeBlanc < sommeNoir && sommeBlanc < sommeRouge)
						|| sommeNoir == sommeRouge && sommeNoir > sommeBlanc)
					tour.gagnant = Couleur.BLANC;
				else if ((sommeNoir < sommeBlanc && sommeNoir < sommeRouge)
						|| sommeBlanc == sommeRouge && sommeBlanc > sommeNoir)
					tour.gagnant = Couleur.NOIR;
			}
		},
		PLUS_GRAND_ECART {
			void calculerLinkGagnant(Tour tour) {
				int minRouge = 7, minNoir = 7, minBlanc = 7, maxRouge = 0, maxNoir = 0, maxBlanc = 0;
				int[] rouges = tour.desRouges();
				int[] noirs = tour.desNoirs();
				int[] blancs = tour.desBlancs();
				for (int i = 0; i < rouges.length; i++) {
					if (rouges[i] < minRouge)
						minRouge = rouges[i];
					else if (rouges[i] > maxRouge)
						maxRouge = rouges[i];
				}
				for (int i = 0; i < noirs.length; i++) {
					if (noirs[i] < minNoir)
						minNoir = noirs[i];
					else if (noirs[i] > maxNoir)
						maxNoir = noirs[i];
				}
				for (int i = 0; i < blancs.length; i++) {
					if (blancs[i] < minBlanc)
						minBlanc = blancs[i];
					else if (blancs[i] > maxBlanc)
						maxBlanc = blancs[i];
				}
				int ecartRouge = maxRouge - minRouge, ecartNoir = maxNoir
						- minNoir, ecartBlanc = maxBlanc - minBlanc;
				if ((ecartRouge == ecartNoir && ecartRouge >= ecartBlanc)
						|| (ecartRouge == ecartBlanc && ecartRouge >= ecartNoir)
						|| (ecartNoir == ecartBlanc && ecartNoir >= ecartRouge))
					tour.gagnant = Couleur.GRIS;
				else if ((ecartRouge > ecartNoir && ecartRouge > ecartBlanc)
						|| ecartNoir == ecartBlanc && ecartNoir < ecartRouge)
					tour.gagnant = Couleur.ROUGE;
				else if ((ecartBlanc > ecartNoir && ecartBlanc > ecartRouge)
						|| ecartNoir == ecartRouge && ecartNoir < ecartBlanc)
					tour.gagnant = Couleur.BLANC;
				else if ((ecartNoir > ecartBlanc && ecartNoir > ecartRouge)
						|| ecartBlanc == ecartRouge && ecartBlanc < ecartNoir)
					tour.gagnant = Couleur.NOIR;
			}
		},
		PLUS_GRAND_NOMBRE_D_IMPAIR {
			void calculerLinkGagnant(Tour tour) {
				int nbImpairRouge = 0, nbImpairNoir = 0, nbImpairBlanc = 0;
				int[] rouges = tour.desRouges();
				int[] noirs = tour.desNoirs();
				int[] blancs = tour.desBlancs();
				for (int i = 0; i < rouges.length; i++) {
					if ((rouges[i] % 2) == 1)
						nbImpairRouge++;
				}
				for (int i = 0; i < noirs.length; i++) {
					if ((noirs[i] % 2) == 1)
						nbImpairNoir++;
				}
				for (int i = 0; i < blancs.length; i++) {
					if ((blancs[i] % 2) == 1)
						nbImpairBlanc++;
				}
				if ((nbImpairRouge == nbImpairNoir && nbImpairRouge >= nbImpairBlanc)
						|| (nbImpairRouge == nbImpairBlanc && nbImpairRouge >= nbImpairNoir)
						|| (nbImpairNoir == nbImpairBlanc && nbImpairNoir >= nbImpairRouge))
					tour.gagnant = Couleur.GRIS;
				else if ((nbImpairRouge > nbImpairNoir && nbImpairRouge > nbImpairBlanc)
						|| nbImpairNoir == nbImpairBlanc
						&& nbImpairNoir < nbImpairRouge)
					tour.gagnant = Couleur.ROUGE;
				else if ((nbImpairBlanc > nbImpairNoir && nbImpairBlanc > nbImpairRouge)
						|| nbImpairNoir == nbImpairRouge
						&& nbImpairNoir < nbImpairBlanc)
					tour.gagnant = Couleur.BLANC;
				else if ((nbImpairNoir > nbImpairBlanc && nbImpairNoir > nbImpairRouge)
						|| nbImpairBlanc == nbImpairRouge
						&& nbImpairBlanc < nbImpairNoir)
					tour.gagnant = Couleur.NOIR;
			}
		},
		PLUS_GRAND_NOMBRE_DE_PAIR {
			void calculerLinkGagnant(Tour tour) {
				int nbPairRouge = 0, nbPairNoir = 0, nbPairBlanc = 0;
				int[] rouges = tour.desRouges();
				int[] noirs = tour.desNoirs();
				int[] blancs = tour.desBlancs();
				for (int i = 0; i < rouges.length; i++) {
					if ((rouges[i] % 2) == 0)
						nbPairRouge++;
				}
				for (int i = 0; i < noirs.length; i++) {
					if ((noirs[i] % 2) == 0)
						nbPairNoir++;
				}
				for (int i = 0; i < blancs.length; i++) {
					if ((blancs[i] % 2) == 0)
						nbPairBlanc++;
				}
				if ((nbPairRouge == nbPairNoir && nbPairRouge >= nbPairBlanc)
						|| (nbPairRouge == nbPairBlanc && nbPairRouge >= nbPairNoir)
						|| (nbPairNoir == nbPairBlanc && nbPairNoir >= nbPairRouge))
					tour.gagnant = Couleur.GRIS;
				else if ((nbPairRouge > nbPairNoir && nbPairRouge > nbPairBlanc)
						|| nbPairNoir == nbPairBlanc
						&& nbPairNoir < nbPairRouge)
					tour.gagnant = Couleur.ROUGE;
				else if ((nbPairBlanc > nbPairNoir && nbPairBlanc > nbPairRouge)
						|| nbPairNoir == nbPairRouge
						&& nbPairNoir < nbPairBlanc)
					tour.gagnant = Couleur.BLANC;
				else if ((nbPairNoir > nbPairBlanc && nbPairNoir > nbPairRouge)
						|| nbPairBlanc == nbPairRouge
						&& nbPairBlanc < nbPairNoir)
					tour.gagnant = Couleur.NOIR;
			}
		},
		PLUS_HAUTE_VALEUR {
			void calculerLinkGagnant(Tour tour) {
				int maxRouge = 0, maxNoir = 0, maxBlanc = 0;
				int[] rouges = tour.desRouges();
				int[] noirs = tour.desNoirs();
				int[] blancs = tour.desBlancs();
				for (int i = 0; i < rouges.length; i++) {
					if (rouges[i] > maxRouge)
						maxRouge = rouges[i];
				}
				for (int i = 0; i < noirs.length; i++) {
					if (noirs[i] > maxNoir)
						maxNoir = noirs[i];
				}
				for (int i = 0; i < blancs.length; i++) {
					if (blancs[i] > maxBlanc)
						maxBlanc = blancs[i];
				}
				if ((maxRouge == maxNoir && maxRouge >= maxBlanc)
						|| (maxRouge == maxBlanc && maxRouge >= maxNoir)
						|| (maxNoir == maxBlanc && maxNoir >= maxRouge))
					tour.gagnant = Couleur.GRIS;
				else if ((maxRouge > maxNoir && maxRouge > maxBlanc)
						|| maxNoir == maxBlanc && maxNoir < maxRouge)
					tour.gagnant = Couleur.ROUGE;
				else if ((maxBlanc > maxNoir && maxBlanc > maxRouge)
						|| maxNoir == maxRouge && maxNoir < maxBlanc)
					tour.gagnant = Couleur.BLANC;
				else if ((maxNoir > maxBlanc && maxNoir > maxRouge)
						|| maxBlanc == maxRouge && maxBlanc < maxNoir)
					tour.gagnant = Couleur.NOIR;
			}
		};
		void calculerLinkGagnant(Tour tour) {

		}

	}

	static {
		table = new DeOrdre[6];
		table[0] = DeOrdre.PLUS_GRANDE_SOMME;
		table[1] = DeOrdre.PLUS_PETITE_SOMME;
		table[2] = DeOrdre.PLUS_GRAND_ECART;
		table[3] = DeOrdre.PLUS_GRAND_NOMBRE_D_IMPAIR;
		table[4] = DeOrdre.PLUS_GRAND_NOMBRE_DE_PAIR;
		table[5] = DeOrdre.PLUS_HAUTE_VALEUR;
	}

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@OneToMany(cascade = { CascadeType.ALL })
	@JoinColumn(name = "TOUR_ID")
	//@MapKeyJoinColumn(name = "JOUEUR_ID")
	@MapKeyColumn(name = "JOUEUR_ID")
	private Map<Joueur, Action> joueursAction = new HashMap<Joueur, Action>();

	@Enumerated(EnumType.STRING)
	private DeOrdre deOrdre;

	@OneToMany(cascade = { CascadeType.ALL })
	@JoinColumn(name = "TOUR_ID")
	private List<De> des = new ArrayList<De>();

	@Transient
	private Timer timer;

	@Transient
	private Couleur gagnant;

	@Transient
	private Partie partie;

	public Tour() {
	}
	
	public Map<Joueur, Action> getJoueursAction() {
		return joueursAction;
	}	

	public DeOrdre lancerDeOrdre() {
		Random r = new Random();
		int valeur = 0 + r.nextInt(5);// Genere un nombre entre 0 et 5
		return table[valeur];
	}

	public Couleur getGagnant() {
		return gagnant;
	}

	public void lancerDes() {
		Random r = new Random();
		for (int i = 0; i < 3; i++) {
			De d = new De(1 + r.nextInt(6), Couleur.BLANC);
			des.add(d);
		}
		for (int i = 0; i < 3; i++) {
			De d = new De(1 + r.nextInt(6), Couleur.NOIR);
			des.add(d);
		}
		for (int i = 0; i < 3; i++) {
			De d = new De(1 + r.nextInt(6), Couleur.ROUGE);
			des.add(d);
		}
	}

	public Set<Entry<Joueur, Action>> actions() {
		return joueursAction.entrySet();
	}

	public boolean dejaUnLink(Joueur j) {
		if (joueursAction.containsKey(j))
			return true;
		return false;
	}

	public int getId() {
		return id;
	}

	public DeOrdre getDeOrdre() {
		return deOrdre;
	}

	public void setDeOrdre(DeOrdre deOrdre) {
		this.deOrdre = deOrdre;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	public List<De> getDes() {
		return des;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Tour other = (Tour) obj;
		if (id != other.id)
			return false;
		return true;
	}

	public void jouerLeTour(Partie p) {
		this.partie = p;
		deOrdre = lancerDeOrdre();
		deOrdre.calculerLinkGagnant(this);
		lancerDes();
	}

	
	@Override
	public String toString() {
		return "Tour [id=" + id + ", joueursAction=" + joueursAction
				+ ", deOrdre=" + deOrdre + ", des=" + des + ", gagnant="
				+ gagnant + ", partie=" + partie + "]";
	}

	public void calculerLinkGagnant() {
		deOrdre.calculerLinkGagnant(this);
	}

	public int[] desRouges() {
		int[] desRouges = new int[3];
		Iterator<De> it = this.des.iterator();
		int i = 0;
		while (it.hasNext()) {
			De de = it.next();
			if (de.getCouleur().equals(Couleur.ROUGE))
				desRouges[i++] = de.getValeur();
		}
		return desRouges;
	}

	public int[] desNoirs() {
		int[] desNoirs = new int[3];
		Iterator<De> it = this.des.iterator();
		int i = 0;
		while (it.hasNext()) {
			De de = it.next();
			if (de.getCouleur().equals(Couleur.NOIR))
				desNoirs[i++] = de.getValeur();
		}
		return desNoirs;
	}

	public int[] desBlancs() {
		int[] desBlancs = new int[3];
		Iterator<De> it = this.des.iterator();
		int i = 0;
		while (it.hasNext()) {
			De de = it.next();
			if (de.getCouleur().equals(Couleur.BLANC))
				desBlancs[i++] = de.getValeur();
		}
		return desBlancs;
	}
}
